package br.pucrio.inf.tamdera.mapping;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

import org.eclipse.emf.common.util.EList;


import br.pucrio.inf.tamdera.ConceptDeclaration;
import br.pucrio.inf.tamdera.ConceptMap;
import br.pucrio.inf.tamdera.NameClassMapping;
import br.pucrio.inf.tamdera.PackageMapping;
import br.pucrio.inf.tamdera.Paragraph;
import br.pucrio.inf.tamdera.ParentMapping;
import br.pucrio.inf.tamdera.PrefixMapping;
import br.pucrio.inf.tamdera.RegExpressionMapping;
import br.pucrio.inf.tamdera.RulesSpecification;
import br.pucrio.inf.tamdera.SuffixMapping;
import br.pucrio.inf.tamdera.prolog.PrologRepresentationManager;
import br.pucrio.inf.tamdera.prolog.utils.PrologIntegrationConstants;
import br.pucrio.inf.tamdera.utils.ConverterPrologTamderaUtils;

public class MappingExtractorVisitor 
{

	public MappingExtractorVisitor(List<String> nameOfClasses, PrologRepresentationManager prologManager) {
		super();
		this.nameOfClasses = nameOfClasses;
		conceptMapping = new HashMap<String, List<String>>();
		this.prologManager = prologManager;
	}
	
	/*used to query subclasses of a given parent class mapping*/
	private PrologRepresentationManager prologManager; 
	
	private List<String> nameOfClasses;

	private HashMap<String, List<String>> conceptMapping;

	protected void _extractConceptMapping(final RulesSpecification spec) 
	{
		EList<Paragraph> paragraphs = spec.getParagraphs();
		for (Paragraph para : paragraphs )
		{
			_extractConceptMapping( para );
		}
	}

	protected void _extractConceptMapping(final ConceptDeclaration decl) 
	{
		String concept = decl.getName();
		ConceptMap mapper = decl.getConceptMapper();
		_extractConceptMapping( mapper , concept);
	}


	protected void _extractConceptMapping(final RegExpressionMapping mapping, final String conceptName) 
	{
		String regExpr = mapping.getRegExpression();

		List<String> mappedClasses = new ArrayList<String>();

		for ( String classNameWithPackage : nameOfClasses )
		{
			if (classNameWithPackage.matches( regExpr ) )
			{
				mappedClasses.add( classNameWithPackage );
			}
		}

		conceptMapping.put( conceptName, mappedClasses );
	}

	
	private String removeQuotationOfName ( String packageName )
	{
		return packageName.substring( 1, packageName.length() - 1 );
	}
	
	protected void _extractConceptMapping(final PackageMapping mapping, final String conceptName) 
	{
		String packageName = mapping.getPackageName();

		//removing quotation mark
		packageName = removeQuotationOfName( packageName );

		List<String> mappedClasses = new ArrayList<String>();

		for ( String classNameWithPackage : nameOfClasses )
		{
			if (classNameWithPackage.startsWith( packageName ) )
			{
				mappedClasses.add( classNameWithPackage );
			}
		}

		conceptMapping.put( conceptName, mappedClasses );
	}

	protected void _extractConceptMapping(final SuffixMapping mapping, final String conceptName) 
	{
		String suffix = mapping.getSuffixName();


		List<String> mappedClasses = new ArrayList<String>();

		for ( String classNameWithPackage : nameOfClasses )
		{
			if (classNameWithPackage.endsWith( suffix ) )
			{
				mappedClasses.add( classNameWithPackage );
			}
		}
		conceptMapping.put( conceptName, mappedClasses );
	}

	protected void _extractConceptMapping(final PrefixMapping mapping, final String conceptName) 
	{
		String prefix = mapping.getPrefixName();


		List<String> mappedClasses = new ArrayList<String>();
		
		for ( String classNameWithPackage : nameOfClasses )
		{
			int lastIndexOfPath = classNameWithPackage.lastIndexOf( PrologIntegrationConstants.PACKAGE_SEPARATOR_IN_TAMDERA_DSL );
			
			String classNameStr = classNameWithPackage.substring( lastIndexOfPath + 1, classNameWithPackage.length() );
			
			if (classNameStr.startsWith(prefix))
			{
				mappedClasses.add( classNameWithPackage );
			}
		}
		conceptMapping.put( conceptName, mappedClasses );
	}

	protected void _extractConceptMapping(final NameClassMapping mapping, final String conceptName) 
	{
		String name = mapping.getNameOfClass();


		List<String> mappedClasses = new ArrayList<String>();

		for ( String classNameWithPackage : nameOfClasses )
		{
			int lastIndexOfPath = classNameWithPackage.lastIndexOf( PrologIntegrationConstants.PACKAGE_SEPARATOR_IN_TAMDERA_DSL );
			
			String classNameStr = classNameWithPackage.substring( lastIndexOfPath + 1, classNameWithPackage.length() );
			
			if ( classNameStr.equals( name ) )
			{
				mappedClasses.add( classNameWithPackage );
			}
		}
		conceptMapping.put( conceptName, mappedClasses );
	}

	protected void _extractConceptMapping(final ParentMapping mapping, final String conceptName) 
	{
		String parentName = mapping.getParent();

		//removing quotation mark
		parentName = removeQuotationOfName( parentName );

		List<String> mappedParentClasses = new ArrayList<String>();

		for ( String classNameWithPackage : nameOfClasses )
		{
			int lastIndexOfPath = classNameWithPackage.lastIndexOf( PrologIntegrationConstants.PACKAGE_SEPARATOR_IN_TAMDERA_DSL );
			
			String classNameStr = classNameWithPackage.substring( lastIndexOfPath + 1, classNameWithPackage.length() );
			
			if ( classNameStr.equals( parentName ) )
			{
				mappedParentClasses.add( classNameWithPackage );
			}
		}
		
		//having the super classes, i need to get their children.
		List<String> subClassesInProlog = prologManager.getSubClassesOfClasses( mappedParentClasses );
		List<String> subClassesInTamdera = ConverterPrologTamderaUtils.getConvertedNamesOfPrologClasses( subClassesInProlog );
		mappedParentClasses.addAll( subClassesInTamdera );
		
		conceptMapping.put( conceptName, mappedParentClasses );
		
	}


	public void _extractConceptMapping(final Object term) {
		if (term instanceof RulesSpecification) 
		{
			_extractConceptMapping((RulesSpecification)term);
		} 
		else if (term instanceof ConceptDeclaration) 
		{
			_extractConceptMapping((ConceptDeclaration)term);
		} 
	}
	
	public void _extractConceptMapping(final ConceptMap mapping, final String conceptName) {
		if ( mapping == null )
		{
			return;
		}
	    if (mapping instanceof NameClassMapping) 
	    {
	      _extractConceptMapping((NameClassMapping)mapping, conceptName);
	    } 
	    else if (mapping instanceof PackageMapping) 
	    {
	      _extractConceptMapping((PackageMapping)mapping, conceptName);
	    } 
	    else if (mapping instanceof ParentMapping) 
	    {
	      _extractConceptMapping((ParentMapping)mapping, conceptName);
	    } 
	    else if (mapping instanceof PrefixMapping) 
	    {
	      _extractConceptMapping((PrefixMapping)mapping, conceptName);
	    }
	    else if (mapping instanceof RegExpressionMapping) 
	    {
	      _extractConceptMapping((RegExpressionMapping)mapping, conceptName);
	    }
	    else if (mapping instanceof SuffixMapping) 
	    {
	      _extractConceptMapping((SuffixMapping)mapping, conceptName);
	    }
	    else 
	    {
	      throw new IllegalArgumentException("Unhandled parameter types: " +
	        Arrays.<Object>asList(mapping, conceptName).toString());
	    }
	  }

	public List<String> getNameOfClasses() {
		return nameOfClasses;
	}

	public void setNameOfClasses(List<String> nameOfClasses) {
		this.nameOfClasses = nameOfClasses;
	}

	public HashMap<String, List<String>> getConceptMapping() {
		return conceptMapping;
	}

	public void setConceptMapping(HashMap<String, List<String>> conceptMapping) {
		this.conceptMapping = conceptMapping;
	}


}
